#include <cv.h>
#include <highgui.h>

#include "resourceTracker.h"
#include "handlocaliser.hpp"


//this looks up the location of the gtest files in header hiDependenciesForTestFramework.h
//TODO : Design choice? currently I'll keep this dependency in a very specific header file
// as changing it should cause minimal recompilation.

#include "hiDependenciesForTestFramework.h"
#include HI_DEPENDENCY_GTEST_HEADER

using namespace cv;

namespace {
	
	// The fixture for testing class HandLocaliser.
	class HandLocaliserTest : public ::testing::Test {
	public:
		
		ResourceTracker* rt;
		HandLocaliser* hl;
	
		virtual void SetUp() {
			try {
				rt = new ResourceTracker( "../config/runtimeSettings/cfg.xml" ); //TODO even later binding?
				rt->loadCategory("TestData");
				
				hl = new HandLocaliser();
			}
			catch (cv::Exception& e) {
				ASSERT_TRUE(false); //Test failed!
			}
		}
		
		virtual void TearDown() {
			delete rt;
			rt = 0;
			
			delete hl;
			hl = 0;
		}

	};
	
	
	TEST_F(HandLocaliserTest, HandLocaliserFindsHandOfTom ) {
		Mat testImg = rt->getMat("handL_back_tom");
		
		Rect handRect = hl->localiseHand( testImg );
		
		Point groundTruthHandLocation = rt->getPointTag("handL_back_tom");
		
		bool testResult = handRect.x < groundTruthHandLocation.x && groundTruthHandLocation.x < (handRect.x + handRect.width); //Point x-coord in bounding box
		testResult &= handRect.y < groundTruthHandLocation.y && groundTruthHandLocation.y < (handRect.y + handRect.height); //Point y-coord in bounding box
		
#ifdef HI_TEST_VISUALISATION
		//Visualise hand location and ground truth location
		{
			Mat visualisation_image;
			
			testImg.copyTo( visualisation_image );
			
			int clippedHandWidth = (handRect.width < visualisation_image.cols - handRect.x ) ? handRect.width : visualisation_image.cols - handRect.x;
			int clippedHandHeight = (handRect.height < visualisation_image.rows - handRect.y ) ? handRect.height : visualisation_image.rows - handRect.y;
			int clippedHandX = (0 < handRect.x) ? handRect.x : 0;
			int clippedHandY = (0 < handRect.y) ? handRect.y : 0;
			
			//Draw hand location as found by handLocaliser
			rectangle( visualisation_image, Point( clippedHandX, clippedHandY ),
					  Point( clippedHandX+clippedHandWidth, clippedHandY + clippedHandHeight ),
					  Scalar::all(250),
					  2);
			
			//Draw ground truth location as found by handLocaliser
			circle( visualisation_image, Point( groundTruthHandLocation.x, groundTruthHandLocation.y ), 1, //radius 1
				   Scalar(0,255,0), 2); //thickness 2
			
			namedWindow( "handL_back_tom localisation", 1 );
			imshow( "handL_back_tom localisation", visualisation_image );
			
			waitKey();
		}
#endif
		
		ASSERT_TRUE( testResult );
	}
	
	TEST_F(HandLocaliserTest, HandLocaliserDoesNotFindWrongTag) {
		Mat testImg = rt->getMat("handL_back_tom_WrongTag");
		
		Rect handRect = hl->localiseHand( testImg );
		
		Point groundTruthHandLocation = rt->getPointTag("handL_back_tom_WrongTag");
		
		bool testResult = handRect.x < groundTruthHandLocation.x && groundTruthHandLocation.x < (handRect.x + handRect.width); //Point x-coord in bounding box
		testResult &= handRect.y < groundTruthHandLocation.y && groundTruthHandLocation.y < (handRect.y + handRect.height); //Point y-coord in bounding box
		
#ifdef HI_TEST_VISUALISATION
		//Visualise hand location and ground truth location
		{
			Mat visualisation_image;
			
			testImg.copyTo( visualisation_image );
			
			int clippedHandWidth = (handRect.width < visualisation_image.cols - handRect.x ) ? handRect.width : visualisation_image.cols - handRect.x;
			int clippedHandHeight = (handRect.height < visualisation_image.rows - handRect.y ) ? handRect.height : visualisation_image.rows - handRect.y;
			int clippedHandX = (0 < handRect.x) ? handRect.x : 0;
			int clippedHandY = (0 < handRect.y) ? handRect.y : 0;
			
			//Draw hand location as found by handLocaliser
			rectangle( visualisation_image, Point( clippedHandX, clippedHandY ),
					  Point( clippedHandX+clippedHandWidth, clippedHandY + clippedHandHeight ),
					  Scalar::all(250),
					  2);
			
			//Draw ground truth location as found by handLocaliser
			circle( visualisation_image, Point( groundTruthHandLocation.x, groundTruthHandLocation.y ), 1, //radius 1
				   Scalar(0,255,0), 2); //thickness 2
			
			namedWindow( "handL_back_tom_WrongTag localisation", 1 );
			imshow( "handL_back_tom_WrongTag localisation", visualisation_image );
			
			waitKey();
		}
#endif
		
		ASSERT_FALSE( testResult ); //tag was wrong, so it should not fall inside bounding box
	}
		
		TEST_F(HandLocaliserTest, HandLocaliserFindsHandOfDave ) {
			Mat testImg = rt->getMat("handL_back_dave");
			
			Rect handRect = hl->localiseHand( testImg );
			
			Point groundTruthHandLocation = rt->getPointTag("handL_back_dave");
			
			bool testResult = handRect.x < groundTruthHandLocation.x && groundTruthHandLocation.x < (handRect.x + handRect.width); //Point x-coord in bounding box
			testResult &= handRect.y < groundTruthHandLocation.y && groundTruthHandLocation.y < (handRect.y + handRect.height); //Point y-coord in bounding box
			
#ifdef HI_TEST_VISUALISATION
			//Visualise hand location and ground truth location
			{
				Mat visualisation_image;
				
				testImg.copyTo( visualisation_image );
				
				int clippedHandWidth = (handRect.width < visualisation_image.cols - handRect.x ) ? handRect.width : visualisation_image.cols - handRect.x;
				int clippedHandHeight = (handRect.height < visualisation_image.rows - handRect.y ) ? handRect.height : visualisation_image.rows - handRect.y;
				int clippedHandX = (0 < handRect.x) ? handRect.x : 0;
				int clippedHandY = (0 < handRect.y) ? handRect.y : 0;
				
				//Draw hand location as found by handLocaliser
				rectangle( visualisation_image, Point( clippedHandX, clippedHandY ),
						  Point( clippedHandX+clippedHandWidth, clippedHandY + clippedHandHeight ),
						  Scalar::all(250),
						  2);
				
				//Draw ground truth location as found by handLocaliser
				circle( visualisation_image, Point( groundTruthHandLocation.x, groundTruthHandLocation.y ), 1, //radius 1
					   Scalar(0,255,0), 2); //thickness 2
				
				namedWindow( "handL_back_dave localisation", 1 );
				imshow( "handL_back_dave localisation", visualisation_image );
				
				waitKey();
			}
			
#endif
		
		ASSERT_TRUE( testResult );
	}
	
	TEST_F(HandLocaliserTest, HandLocaliserFindsHandNearEdge ) {
		Mat testImg = rt->getMat("handL_near_edge");
		
		Rect handRect = hl->localiseHand( testImg );
		
		Point groundTruthHandLocation = rt->getPointTag("handL_near_edge");
		
		bool testResult = handRect.x < groundTruthHandLocation.x && groundTruthHandLocation.x < (handRect.x + handRect.width); //Point x-coord in bounding box
		testResult &= handRect.y < groundTruthHandLocation.y && groundTruthHandLocation.y < (handRect.y + handRect.height); //Point y-coord in bounding box
		
#ifdef HI_TEST_VISUALISATION
		//Visualise hand location and ground truth location
		{
			Mat visualisation_image;
			
			testImg.copyTo( visualisation_image );
			
			int clippedHandWidth = (handRect.width < visualisation_image.cols - handRect.x ) ? handRect.width : visualisation_image.cols - handRect.x;
			int clippedHandHeight = (handRect.height < visualisation_image.rows - handRect.y ) ? handRect.height : visualisation_image.rows - handRect.y;
			int clippedHandX = (0 < handRect.x) ? handRect.x : 0;
			int clippedHandY = (0 < handRect.y) ? handRect.y : 0;
			
			//Draw hand location as found by handLocaliser
			rectangle( visualisation_image, Point( clippedHandX, clippedHandY ),
					  Point( clippedHandX+clippedHandWidth, clippedHandY + clippedHandHeight ),
					  Scalar::all(250),
					  2);
			
			//Draw ground truth location as found by handLocaliser
			circle( visualisation_image, Point( groundTruthHandLocation.x, groundTruthHandLocation.y ), 1, //radius 1
				   Scalar(0,255,0), 2); //thickness 2
			
			namedWindow( "handL_near_edge localisation", 1 );
			imshow( "handL_near_edge localisation", visualisation_image );
			
			waitKey();
		}		
#endif
		
		ASSERT_TRUE( testResult );
	}

}  // namespace




